/*

    json.js

    2006-04-28



    This file adds these methods to JavaScript:



        object.toJSONString()



            This method produces a JSON text from an object. The

            object must not contain any cyclical references.



        array.toJSONString()



            This method produces a JSON text from an array. The

            array must not contain any cyclical references.



        string.parseJSON()



            This method parses a JSON text to produce an object or

            array. It will return false if there is an error.

*/

(function () {

    var m = {

            '\b': '\\b',

            '\t': '\\t',

            '\n': '\\n',

            '\f': '\\f',

            '\r': '\\r',

            '"' : '\\"',

            '\\': '\\\\'

        },

        s = {

            array: function (x) {

                var a = ['['], b, f, i, l = x.length, v;

                for (i = 0; i < l; i += 1) {

                    v = x[i];

                    f = s[typeof v];

                    if (f) {

                        v = f(v);

                        if (typeof v == 'string') {

                            if (b) {

                                a[a.length] = ',';

                            }

                            a[a.length] = v;

                            b = true;

                        }

                    }

                }

                a[a.length] = ']';

                return a.join('');

            },

            'boolean': function (x) {

                return String(x);

            },

            'null': function (x) {

                return "null";

            },

            number: function (x) {

                return isFinite(x) ? String(x) : 'null';

            },

            object: function (x) {

                if (x) {

                    if (x instanceof Array) {

                        return s.array(x);

                    }

                    var a = ['{'], b, f, i, v;

                    for (i in x) {

                        v = x[i];

                        f = s[typeof v];

                        if (f) {

                            v = f(v);

                            if (typeof v == 'string') {

                                if (b) {

                                    a[a.length] = ',';

                                }

                                a.push(s.string(i), ':', v);

                                b = true;

                            }

                        }

                    }

                    a[a.length] = '}';

                    return a.join('');

                }

                return 'null';

            },

            string: function (x) {

                if (/["\\\x00-\x1f]/.test(x)) {

                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {

                        var c = m[b];

                        if (c) {

                            return c;

                        }

                        c = b.charCodeAt();

                        return '\\u00' +

                            Math.floor(c / 16).toString(16) +

                            (c % 16).toString(16);

                    });

                }

                return '"' + x + '"';

            }

        };



    Object.prototype.toJSONString = function () {

        return s.object(this);

    };



    Array.prototype.toJSONString = function () {

        return s.array(this);

    };

})();



String.prototype.parseJSON = function () {

    /*try {

        return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(

                this.replace(/"(\\.|[^"\\])*"/g, ''))) &&

            eval('(' + this + ')');

    } catch (e) {

        return false;

    }*/

    

    //in IE the test is way too slow, turn it off for now, if it returns false

    //our ajax code cannot run anyways

    return eval('(' + this + ')');

};



/**

 * when an object is passed from server to client using JSON format,

 * the server's Date object is only mapped into a plain JSON Object instead of Date.

 * To transform Object to Date, call 

 *

 * getLocalizedDate(original_json_object)     to get a date according to client's timezone

 * getNonlocalizedDate(original_json_object)  to get a date according to server's data

 */

function getLocalizedDate(jsonDateObject) {

  return new Date(jsonDateObject.time);

}



function getNonlocalizedDate(jsonDateObject) {

  return new Date(jsonDateObject.year + 1900,

                  jsonDateObject.month,

                  jsonDateObject.date,

                  jsonDateObject.hours,

                  jsonDateObject.minutes,

                  jsonDateObject.seconds,

                  0);

}



// a global month names array

var gsMonthNames = new Array(

  'January',

  'February',

  'March',

  'April',

  'May',

  'June',

  'July',

  'August',

  'September',

  'October',

  'November',

  'December'

);



// a global day names array

var gsDayNames = new Array(

  'Sunday',

  'Monday',

  'Tuesday',

  'Wednesday',

  'Thursday',

  'Friday',

  'Saturday'

);



function _dateDiff(date) {

  var thatDay = new Date(date.getTime());

  thatDay.setHours(0);

  thatDay.setMinutes(0);

  thatDay.setSeconds(0);

  thatDay.setMilliseconds(0);

  var diff = new Date().getTime() - thatDay.getTime();

  var dateDiff = Math.floor(diff / 86400000);

  if (dateDiff < 1) 

    return "Today";

  else if (dateDiff < 2)

    return "Yesterday";

  else

    return (dateDiff + " days ago");

}



/** 

 * Formats a javascript date object to a string.

 * The format is a string which pretty much follows Java's SimpleDateFormat.<b>

 *

 * @param f: The format to which the date should be formatted

 * @return: The formatted string  
 */

Date.prototype.format = function(f) {

  if (!this.valueOf())

    return '&nbsp;';

  var d = this;

  return f.replace(/(yyyy|yy|MMMM|MMM|MM|M|EEEE|EEE|DDDD|dd|d|HH|hh|h|mm|ss|a)/g,

    function($1) {

      switch ($1) {

        case 'yyyy': return d.getFullYear();

        case 'yy':   return (d.getFullYear() % 100).zf(2);

        case 'MMMM': return gsMonthNames[d.getMonth()];

        case 'MMM':  return gsMonthNames[d.getMonth()].substr(0, 3);

        case 'MM':   return (d.getMonth() + 1).zf(2);

        case 'M':    return (d.getMonth() + 1);

        case 'EEEE': return gsDayNames[d.getDay()];

        case 'EEE':  return gsDayNames[d.getDay()].substr(0, 3);

        case 'DDDD': return _dateDiff(d);

        case 'dd':   return d.getDate().zf(2);

        case 'd':    return d.getDate();

        case 'HH':   return d.getHours().zf(2);

        case 'hh':   return ((h = d.getHours() % 12) ? h : 12).zf(2);

        case 'h':    return ((h = d.getHours() % 12) ? h : 12);

        case 'mm':   return d.getMinutes().zf(2);

        case 'ss':   return d.getSeconds().zf(2);

        case 'a':    return d.getHours() < 12 ? 'AM' : 'PM';

      }

    }

  );

};



Number.prototype.zf = function(digits) {

  var s = "" + this.valueOf();

  while (s.length < digits) {

    s = "0" + s;

  }

  return s;

};